package com.jl.card.gp;

import java.io.IOException;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.annotations.JSStaticFunction;

import com.jl.js.filepath.FilePathUtil;
import com.jl.util.HexUtil;

import de.cardcontact.opencard.service.isocard.IsoConstants;
import de.cardcontact.opencard.utils.CapFile;
import opencard.core.terminal.CardTerminalException;
import opencard.core.terminal.CommandAPDU;

public class GPTool extends ScriptableObject {
	
	//private static GPTool gptool = new GPTool();

	private static final String SPLIT = "#";

	/**
	 * Issue INSTALL command with INSTALL FOR INSTALL and SELECTABLE option to
	 * security domain
	 * 
	 * @param loadFileAID
	 *            AID for load file in card
	 * @param execModAID
	 *            AID for module contained in load file
	 * @param appInsAID
	 *            AID for application instance
	 * @param privileges
	 *            Privileges for application
	 * @param installParam
	 *            Install parameter for application
	 * @param installToken
	 *            Install tokens
	 * @return ResponseAPDU from card
	 */
	@JSStaticFunction
	public static String installForInstallAndSelectable(String _loadFileAID,
			String _execModAID, String _appInsAID, String _privileges,
			String _installParam, String _installToken) {
		byte[] loadFileAID = HexUtil.parseHexToByteArray(_loadFileAID);
		byte[] execModAID = HexUtil.parseHexToByteArray(_execModAID);
		byte[] appInsAID = HexUtil.parseHexToByteArray(_appInsAID);
		byte[] privileges = HexUtil.parseHexToByteArray(_privileges);
		byte[] installParam = HexUtil.parseHexToByteArray(_installParam);
		byte[] installToken = HexUtil.parseHexToByteArray(_installToken);

		CommandAPDU com = new CommandAPDU(262);
		com.setLength(0);
		com.append(IsoConstants.CLA_EMV);
		com.append(IsoConstants.INS_INSTALL);
		com.append((byte) 0x0C);
		com.append((byte) 0x00);

		com.append((byte) 0x00);

		com.append((byte) loadFileAID.length);
		com.append(loadFileAID);

		com.append((byte) execModAID.length);
		com.append(execModAID);

		com.append((byte) appInsAID.length);
		com.append(appInsAID);

		com.append((byte) privileges.length);
		com.append(privileges);

		com.append((byte) installParam.length);
		com.append(installParam);

		if (installToken != null) {
			com.append((byte) installToken.length);
			com.append(installToken);
		} else {
			com.append((byte) 0x00);
		}

		com.setByte(4, com.getLength() - 5);

		return HexUtil.toHexString(com.getBytes());
	}

	/**
	 * Issue INSTALL command with INSTALL FOR LOAD option to security domain
	 * 
	 * @param loadFileAID
	 * @param secDomAID
	 * @param loadDBHash
	 * @param loadParam
	 * @param loadToken
	 * @return ResponseAPDU from card
	 */
	@JSStaticFunction
	public static String installForLoad(String _loadFileAID, String _secDomAID,
			String _loadDBHash, String _loadParam, String _loadToken) {

		byte[] loadFileAID = HexUtil.parseHexToByteArray(_loadFileAID);
		byte[] loadDBHash = HexUtil.parseHexToByteArray(_loadDBHash);
		byte[] loadParam = HexUtil.parseHexToByteArray(_loadParam);
		byte[] loadToken = HexUtil.parseHexToByteArray(_loadToken);
		byte[] secDomAID = HexUtil.parseHexToByteArray(_secDomAID);

		CommandAPDU com = new CommandAPDU(262);

		com.setLength(0);
		com.append(IsoConstants.CLA_EMV);
		com.append(IsoConstants.INS_INSTALL);
		com.append((byte) 0x02);
		com.append((byte) 0x00);

		com.append((byte) 0x00);

		com.append((byte) loadFileAID.length);
		com.append(loadFileAID);

		if (secDomAID != null) {
			com.append((byte) secDomAID.length);
			com.append(secDomAID);
		} else {
			com.append((byte) 0x00);
		}

		if (loadDBHash != null) {
			com.append((byte) loadDBHash.length);
			com.append(loadDBHash);
		} else {
			com.append((byte) 0x00);
		}

		if (loadParam != null) {
			com.append((byte) loadParam.length);
			com.append(loadParam);
		} else {
			com.append((byte) 0x00);
		}

		if (loadToken != null) {
			com.append((byte) loadToken.length);
			com.append(loadToken);
		} else {
			com.append((byte) 0x00);
		}

		com.setByte(4, com.getLength() - 5);

		return HexUtil.toHexString(com.getBytes());
	}

	/**
	 * Load load file into card using a sequence of LOAD apdus
	 * 
	 * @param capFile
	 *            Load file with cap components
	 * 
	 * @return Response from last LOAD commands
	 * @throws IOException
	 */
	@JSStaticFunction
	public static String[] load(String path,int maxBlockSize) throws IOException {
		if(maxBlockSize > 0xFF || maxBlockSize <=0){
			throw new IndexOutOfBoundsException("maxBlockSize should >0 and <=0xFF");
		}
		CapFile capFile = new CapFile(FilePathUtil.getJSFilePath(path).getAbsolutePath());
		capFile.read();
		StringBuilder sb = new StringBuilder(1024 * 10);
		CommandAPDU com = new CommandAPDU(262);

		byte[] loadFile = capFile.getLoadFile(CapFile.CAPSEQUENCE);
		int length = loadFile.length;
		int offset = 0;
		int block;
		int count = 0;

		while (length > 0) {
			block = length;
			if (block > maxBlockSize) {
				block = maxBlockSize;
			}
			length -= block;

			com.setLength(0);
			com.append(IsoConstants.CLA_EMV);
			com.append(IsoConstants.INS_LOAD);
			com.append((byte) (length > 0 ? 0x00 : 0x80)); // Last block ?
			com.append((byte) count);
			com.append((byte) block);

			System.arraycopy(loadFile, offset, com.getBuffer(), 5, block);
			com.setLength(block + 5);
			sb.append(HexUtil.toHexString(com.getBytes())).append(SPLIT);

			count++;
			offset += block;
		}
		String[] temps = sb.toString().split(SPLIT);
		return temps;
//		Object[] objs = new Object[temps.length];
//		int i = 0;
//		for(String str : temps){
//			objs[i++] = str;
//		}
//		Context contex = Context.getCurrentContext();
//		Scriptable parent = ScriptableObject.getTopLevelScope(gptool);
//		return contex.newArray(parent, objs);
	}

	/**
	 * Issue DELETE command to remove package with given AID from card
	 * 
	 * @param aid
	 * @return ResponseAPDU from card
	 * @throws CardTerminalException
	 */
	@JSStaticFunction
	public static String deleteAID(String strAid,boolean isForce) {

		byte[] aid = HexUtil.parseHexToByteArray(strAid);
		CommandAPDU com = new CommandAPDU(262);

		com.setLength(0);
		com.append(IsoConstants.CLA_EMV);
		com.append(IsoConstants.INS_DELETE_FILE);
		com.append((byte) 0x00);
		com.append(isForce ? (byte) 0x80 : (byte) 0x00);

		com.append((byte) (aid.length + 2));

		com.append((byte) 0x4F);
		com.append((byte) aid.length);
		com.append(aid);

		return HexUtil.toHexString(com.getBytes());
	}

	@Override
	public String getClassName() {
		return "GPTool";
	}

}
